home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectInput / JoyStick / joystick.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  15.0 KB  |  418 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Joystick.cpp
  3. //
  4. // Desc: Demonstrates an application which receives immediate 
  5. //       joystick data in exclusive mode via a dialog timer.
  6. //
  7. // Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #include <windows.h>
  11. #include <basetsd.h>
  12. #include <dinput.h>
  13. #include "resource.h"
  14.  
  15.  
  16.  
  17.  
  18. //-----------------------------------------------------------------------------
  19. // Function-prototypes
  20. //-----------------------------------------------------------------------------
  21. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  22. BOOL CALLBACK    EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext );
  23. BOOL CALLBACK    EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext );
  24. HRESULT InitDirectInput( HWND hDlg );
  25. VOID    FreeDirectInput();
  26. HRESULT UpdateInputState( HWND hDlg );
  27.  
  28.  
  29.  
  30.  
  31. //-----------------------------------------------------------------------------
  32. // Defines, constants, and global variables
  33. //-----------------------------------------------------------------------------
  34. #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
  35. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  36.  
  37. LPDIRECTINPUT8       g_pDI              = NULL;         
  38. LPDIRECTINPUTDEVICE8 g_pJoystick        = NULL;     
  39.  
  40.  
  41.  
  42.  
  43. //-----------------------------------------------------------------------------
  44. // Name: WinMain()
  45. // Desc: Entry point for the application.  Since we use a simple dialog for 
  46. //       user interaction we don't need to pump messages.
  47. //-----------------------------------------------------------------------------
  48. int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, int )
  49. {
  50.     // Display the main dialog box.
  51.     DialogBox( hInst, MAKEINTRESOURCE(IDD_JOYST_IMM), NULL, MainDlgProc );
  52.     
  53.     return TRUE;
  54. }
  55.  
  56.  
  57.  
  58.  
  59. //-----------------------------------------------------------------------------
  60. // Name: MainDialogProc
  61. // Desc: Handles dialog messages
  62. //-----------------------------------------------------------------------------
  63. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  64. {
  65.     switch( msg ) 
  66.     {
  67.         case WM_INITDIALOG:
  68.             if( FAILED( InitDirectInput( hDlg ) ) )
  69.             {
  70.                 MessageBox( NULL, TEXT("Error Initializing DirectInput"), 
  71.                             TEXT("DirectInput Sample"), MB_ICONERROR | MB_OK );
  72.                 EndDialog( hDlg, 0 );
  73.             }
  74.  
  75.             // Set a timer to go off 30 times a second. At every timer message
  76.             // the input device will be read
  77.             SetTimer( hDlg, 0, 1000 / 30, NULL );
  78.             return TRUE;
  79.  
  80.         case WM_ACTIVATE:
  81.             if( WA_INACTIVE != wParam && g_pJoystick )
  82.             {
  83.                 // Make sure the device is acquired, if we are gaining focus.
  84.                 g_pJoystick->Acquire();
  85.             }
  86.             return TRUE;
  87.  
  88.         case WM_TIMER:
  89.             // Update the input device every timer message
  90.             if( FAILED( UpdateInputState( hDlg ) ) )
  91.             {
  92.                 KillTimer( hDlg, 0 );    
  93.                 MessageBox( NULL, TEXT("Error Reading Input State. ") \
  94.                             TEXT("The sample will now exit."), TEXT("DirectInput Sample"), 
  95.                             MB_ICONERROR | MB_OK );
  96.                 EndDialog( hDlg, TRUE ); 
  97.             }
  98.             return TRUE;
  99.  
  100.         case WM_COMMAND:
  101.             switch( LOWORD(wParam) )
  102.             {
  103.                 case IDCANCEL:
  104.                     EndDialog( hDlg, 0 );
  105.                     return TRUE;
  106.             }
  107.  
  108.         case WM_DESTROY:
  109.             // Cleanup everything
  110.             KillTimer( hDlg, 0 );    
  111.             FreeDirectInput();    
  112.             return TRUE;    
  113.     }
  114.  
  115.     return FALSE; // Message not handled 
  116. }
  117.  
  118.  
  119.  
  120.  
  121. //-----------------------------------------------------------------------------
  122. // Name: InitDirectInput()
  123. // Desc: Initialize the DirectInput variables.
  124. //-----------------------------------------------------------------------------
  125. HRESULT InitDirectInput( HWND hDlg )
  126. {
  127.     HRESULT hr;
  128.  
  129.     // Register with the DirectInput subsystem and get a pointer
  130.     // to a IDirectInput interface we can use.
  131.     // Create a DInput object
  132.     if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
  133.                                          IID_IDirectInput8, (VOID**)&g_pDI, NULL ) ) )
  134.         return hr;
  135.  
  136.     // Look for a simple joystick we can use for this sample program.
  137.     if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, 
  138.                                          EnumJoysticksCallback,
  139.                                          NULL, DIEDFL_ATTACHEDONLY ) ) )
  140.         return hr;
  141.  
  142.     // Make sure we got a joystick
  143.     if( NULL == g_pJoystick )
  144.     {
  145.         MessageBox( NULL, TEXT("Joystick not found. The sample will now exit."),  
  146.                     TEXT("DirectInput Sample"), 
  147.                     MB_ICONERROR | MB_OK );
  148.         EndDialog( hDlg, 0 );
  149.         return S_OK;
  150.     }
  151.  
  152.     // Set the data format to "simple joystick" - a predefined data format 
  153.     //
  154.     // A data format specifies which controls on a device we are interested in,
  155.     // and how they should be reported. This tells DInput that we will be
  156.     // passing a DIJOYSTATE2 structure to IDirectInputDevice::GetDeviceState().
  157.     if( FAILED( hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick2 ) ) )
  158.         return hr;
  159.  
  160.     // Set the cooperative level to let DInput know how this device should
  161.     // interact with the system and with other DInput applications.
  162.     if( FAILED( hr = g_pJoystick->SetCooperativeLevel( hDlg, DISCL_EXCLUSIVE | 
  163.                                                              DISCL_FOREGROUND ) ) )
  164.         return hr;
  165.  
  166.     // Enumerate the joystick objects. The callback function enabled user
  167.     // interface elements for objects that are found, and sets the min/max
  168.     // values property for discovered axes.
  169.     if( FAILED( hr = g_pJoystick->EnumObjects( EnumObjectsCallback, 
  170.                                                 (VOID*)hDlg, DIDFT_ALL ) ) )
  171.         return hr;
  172.  
  173.     return S_OK;
  174. }
  175.  
  176.  
  177.  
  178.  
  179. //-----------------------------------------------------------------------------
  180. // Name: EnumJoysticksCallback()
  181. // Desc: Called once for each enumerated joystick. If we find one, create a
  182. //       device interface on it so we can play with it.
  183. //-----------------------------------------------------------------------------
  184. BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
  185.                                      VOID* pContext )
  186. {
  187.     HRESULT hr;
  188.  
  189.     // Obtain an interface to the enumerated joystick.
  190.     hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL );
  191.  
  192.     // If it failed, then we can't use this joystick. (Maybe the user unplugged
  193.     // it while we were in the middle of enumerating it.)
  194.     if( FAILED(hr) ) 
  195.         return DIENUM_CONTINUE;
  196.  
  197.     // Stop enumeration. Note: we're just taking the first joystick we get. You
  198.     // could store all the enumerated joysticks and let the user pick.
  199.     return DIENUM_STOP;
  200. }
  201.  
  202.  
  203.  
  204.  
  205. //-----------------------------------------------------------------------------
  206. // Name: EnumObjectsCallback()
  207. // Desc: Callback function for enumerating objects (axes, buttons, POVs) on a 
  208. //       joystick. This function enables user interface elements for objects
  209. //       that are found to exist, and scales axes min/max values.
  210. //-----------------------------------------------------------------------------
  211. BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
  212.                                    VOID* pContext )
  213. {
  214.     HWND hDlg = (HWND)pContext;
  215.  
  216.     static int nSliderCount = 0;  // Number of returned slider controls
  217.     static int nPOVCount = 0;     // Number of returned POV controls
  218.  
  219.     // For axes that are returned, set the DIPROP_RANGE property for the
  220.     // enumerated axis in order to scale min/max values.
  221.     if( pdidoi->dwType & DIDFT_AXIS )
  222.     {
  223.         DIPROPRANGE diprg; 
  224.         diprg.diph.dwSize       = sizeof(DIPROPRANGE); 
  225.         diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
  226.         diprg.diph.dwHow        = DIPH_BYID; 
  227.         diprg.diph.dwObj        = pdidoi->dwType; // Specify the enumerated axis
  228.         diprg.lMin              = -1000; 
  229.         diprg.lMax              = +1000; 
  230.     
  231.         // Set the range for the axis
  232.         if( FAILED( g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) 
  233.             return DIENUM_STOP;
  234.          
  235.     }
  236.  
  237.  
  238.     // Set the UI to reflect what objects the joystick supports
  239.     if (pdidoi->guidType == GUID_XAxis)
  240.     {
  241.         EnableWindow( GetDlgItem( hDlg, IDC_X_AXIS ), TRUE );
  242.         EnableWindow( GetDlgItem( hDlg, IDC_X_AXIS_TEXT ), TRUE );
  243.     }
  244.     if (pdidoi->guidType == GUID_YAxis)
  245.     {
  246.         EnableWindow( GetDlgItem( hDlg, IDC_Y_AXIS ), TRUE );
  247.         EnableWindow( GetDlgItem( hDlg, IDC_Y_AXIS_TEXT ), TRUE );
  248.     }
  249.     if (pdidoi->guidType == GUID_ZAxis)
  250.     {
  251.         EnableWindow( GetDlgItem( hDlg, IDC_Z_AXIS ), TRUE );
  252.         EnableWindow( GetDlgItem( hDlg, IDC_Z_AXIS_TEXT ), TRUE );
  253.     }
  254.     if (pdidoi->guidType == GUID_RxAxis)
  255.     {
  256.         EnableWindow( GetDlgItem( hDlg, IDC_X_ROT ), TRUE );
  257.         EnableWindow( GetDlgItem( hDlg, IDC_X_ROT_TEXT ), TRUE );
  258.     }
  259.     if (pdidoi->guidType == GUID_RyAxis)
  260.     {
  261.         EnableWindow( GetDlgItem( hDlg, IDC_Y_ROT ), TRUE );
  262.         EnableWindow( GetDlgItem( hDlg, IDC_Y_ROT_TEXT ), TRUE );
  263.     }
  264.     if (pdidoi->guidType == GUID_RzAxis)
  265.     {
  266.         EnableWindow( GetDlgItem( hDlg, IDC_Z_ROT ), TRUE );
  267.         EnableWindow( GetDlgItem( hDlg, IDC_Z_ROT_TEXT ), TRUE );
  268.     }
  269.     if (pdidoi->guidType == GUID_Slider)
  270.     {
  271.         switch( nSliderCount++ )
  272.         {
  273.             case 0 :
  274.                 EnableWindow( GetDlgItem( hDlg, IDC_SLIDER0 ), TRUE );
  275.                 EnableWindow( GetDlgItem( hDlg, IDC_SLIDER0_TEXT ), TRUE );
  276.                 break;
  277.  
  278.             case 1 :
  279.                 EnableWindow( GetDlgItem( hDlg, IDC_SLIDER1 ), TRUE );
  280.                 EnableWindow( GetDlgItem( hDlg, IDC_SLIDER1_TEXT ), TRUE );
  281.                 break;
  282.         }
  283.     }
  284.     if (pdidoi->guidType == GUID_POV)
  285.     {
  286.         switch( nPOVCount++ )
  287.         {
  288.             case 0 :
  289.                 EnableWindow( GetDlgItem( hDlg, IDC_POV0 ), TRUE );
  290.                 EnableWindow( GetDlgItem( hDlg, IDC_POV0_TEXT ), TRUE );
  291.                 break;
  292.  
  293.             case 1 :
  294.                 EnableWindow( GetDlgItem( hDlg, IDC_POV1 ), TRUE );
  295.                 EnableWindow( GetDlgItem( hDlg, IDC_POV1_TEXT ), TRUE );
  296.                 break;
  297.  
  298.             case 2 :
  299.                 EnableWindow( GetDlgItem( hDlg, IDC_POV2 ), TRUE );
  300.                 EnableWindow( GetDlgItem( hDlg, IDC_POV2_TEXT ), TRUE );
  301.  
  302.             case 3 :
  303.                 EnableWindow( GetDlgItem( hDlg, IDC_POV3 ), TRUE );
  304.                 EnableWindow( GetDlgItem( hDlg, IDC_POV3_TEXT ), TRUE );
  305.         }
  306.     }
  307.  
  308.     return DIENUM_CONTINUE;
  309. }
  310.  
  311.  
  312.  
  313.  
  314. //-----------------------------------------------------------------------------
  315. // Name: UpdateInputState()
  316. // Desc: Get the input device's state and display it.
  317. //-----------------------------------------------------------------------------
  318. HRESULT UpdateInputState( HWND hDlg )
  319. {
  320.     HRESULT     hr;
  321.     TCHAR       strText[128]; // Device state text
  322.     DIJOYSTATE2 js;           // DInput joystick state 
  323.     TCHAR*      str;
  324.  
  325.     if( NULL == g_pJoystick ) 
  326.         return S_OK;
  327.  
  328.     // Poll the device to read the current state
  329.     hr = g_pJoystick->Poll(); 
  330.     if( FAILED(hr) )  
  331.     {
  332.         // DInput is telling us that the input stream has been
  333.         // interrupted. We aren't tracking any state between polls, so
  334.         // we don't have any special reset that needs to be done. We
  335.         // just re-acquire and try again.
  336.         hr = g_pJoystick->Acquire();
  337.         while( hr == DIERR_INPUTLOST ) 
  338.             hr = g_pJoystick->Acquire();
  339.  
  340.         // hr may be DIERR_OTHERAPPHASPRIO or other errors.  This
  341.         // may occur when the app is minimized or in the process of 
  342.         // switching, so just try again later 
  343.         return S_OK; 
  344.     }
  345.  
  346.     // Get the input's device state
  347.     if( FAILED( hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE2), &js ) ) )
  348.         return hr; // The device should have been acquired during the Poll()
  349.  
  350.     // Display joystick state to dialog
  351.  
  352.     // Axes
  353.     wsprintf( strText, TEXT("%ld"), js.lX ); 
  354.     SetWindowText( GetDlgItem( hDlg, IDC_X_AXIS ), strText );
  355.     wsprintf( strText, TEXT("%ld"), js.lY ); 
  356.     SetWindowText( GetDlgItem( hDlg, IDC_Y_AXIS ), strText );
  357.     wsprintf( strText, TEXT("%ld"), js.lZ ); 
  358.     SetWindowText( GetDlgItem( hDlg, IDC_Z_AXIS ), strText );
  359.     wsprintf( strText, TEXT("%ld"), js.lRx ); 
  360.     SetWindowText( GetDlgItem( hDlg, IDC_X_ROT ), strText );
  361.     wsprintf( strText, TEXT("%ld"), js.lRy ); 
  362.     SetWindowText( GetDlgItem( hDlg, IDC_Y_ROT ), strText );
  363.     wsprintf( strText, TEXT("%ld"), js.lRz ); 
  364.     SetWindowText( GetDlgItem( hDlg, IDC_Z_ROT ), strText );
  365.  
  366.     // Slider controls
  367.     wsprintf( strText, TEXT("%ld"), js.rglSlider[0] ); 
  368.     SetWindowText( GetDlgItem( hDlg, IDC_SLIDER0 ), strText );
  369.     wsprintf( strText, TEXT("%ld"), js.rglSlider[1] ); 
  370.     SetWindowText( GetDlgItem( hDlg, IDC_SLIDER1 ), strText );
  371.  
  372.     // Points of view
  373.     wsprintf( strText, TEXT("%ld"), js.rgdwPOV[0] );
  374.     SetWindowText( GetDlgItem( hDlg, IDC_POV0 ), strText );
  375.     wsprintf( strText, TEXT("%ld"), js.rgdwPOV[1] );
  376.     SetWindowText( GetDlgItem( hDlg, IDC_POV1 ), strText );
  377.     wsprintf( strText, TEXT("%ld"), js.rgdwPOV[2] );
  378.     SetWindowText( GetDlgItem( hDlg, IDC_POV2 ), strText );
  379.     wsprintf( strText, TEXT("%ld"), js.rgdwPOV[3] );
  380.     SetWindowText( GetDlgItem( hDlg, IDC_POV3 ), strText );
  381.  
  382.    
  383.     // Fill up text with which buttons are pressed
  384.     str = strText;
  385.     for( int i = 0; i < 128; i++ )
  386.     {
  387.         if ( js.rgbButtons[i] & 0x80 )
  388.             str += wsprintf( str, TEXT("%02d "), i );
  389.     }
  390.     *str = 0;   // Terminate the string 
  391.  
  392.     SetWindowText( GetDlgItem( hDlg, IDC_BUTTONS ), strText );
  393.  
  394.     return S_OK;
  395. }
  396.  
  397.  
  398.  
  399.  
  400. //-----------------------------------------------------------------------------
  401. // Name: FreeDirectInput()
  402. // Desc: Initialize the DirectInput variables.
  403. //-----------------------------------------------------------------------------
  404. VOID FreeDirectInput()
  405. {
  406.     // Unacquire the device one last time just in case 
  407.     // the app tried to exit while the device is still acquired.
  408.     if( g_pJoystick ) 
  409.         g_pJoystick->Unacquire();
  410.     
  411.     // Release any DirectInput objects.
  412.     SAFE_RELEASE( g_pJoystick );
  413.     SAFE_RELEASE( g_pDI );
  414. }
  415.  
  416.  
  417.  
  418.